import collections
import datetime
import json
import os
import time
from backtrader.utils.datehelper import current_dt, next_dt, previous_dt
import ccxt
import pandas as pd
import backtrader as bt
import numpy as np
import click
from backtrader.utils.cmd import cli
import warnings
warnings.filterwarnings("ignore")

npv_start_date = "2021-11-08"
params = {
    "binance-main": {
        "start_time": "2021-11-10 12:00:00",   # 跟导出来的日期差八个小时， 这里按照正常时间处理就行
        "transfer_history": [
            ["2021-11-08 11:00:00", 100000],       # 从okex转过来的
            ["2022-03-01 00:00:00", -20000],
            ["2022-03-16 16:30:00", -68000]
        ]
    },
    "binance-main-future": {
        "start_time": "2022-02-27 11:00:00",
        "transfer_history": [
            ["2021-11-08 11:00:00", 0],
            ["2022-03-01 00:00:00", 20000],
            ["2022-03-16 16:30:00", 68000]
        ]
    }
}

"""
现货的时候：
    买入的时候, 扣除手续费是从币扣除：余额得到的=已成交-手续费
    卖出的时候, 扣除手续费是从钱扣除: 余额得到的现金=已成交-手续费
合约的时候:
    开多和开空的时候, 对于余额的影响就是扣除了手续费, 然后锁定保证金
    资金费率结算的时候，也是扣除资金费率，对于余额有影响
    然后等到平多和平空的时候结算，盈亏就会从账户结算
"""
CLOSE_CACHE = dict()


class HoldingItem:
    def __init__(self, asset, type):
        # 资产
        self.asset = asset
        self.type = type
        # 最新更新时间
        self.dt = None
        # 仓位
        self.position = bt.Position()
        # 平仓累计收益(不含手续费)
        self.close_pnl = 0
        # 多头损益
        self.long_pnl = 0
        # 空头损益
        self.short_pnl = 0
        # 开仓累计手续费
        self.fee_usdt = 0
        self.fee_bnb = 0
        self.fee_symbol = 0
        # 交易累计次数
        self.trade_count = 0
        # 多头次数
        self.long_count = 0
        # 空头次数
        self.short_count = 0
        self.win_count = 0
        self.lever = 1

    def update_usdt(self, dt, trade_size):
        self.dt = dt
        return self.position.update(trade_size, 1)

    def update_spot(self, dt, trade_size, trade_price, fee_usdt, fee_bnb, fee_symbol):
        if self.asset == "USDT":
            return
        self.dt = dt

        old_size, old_price = self.position.size, self.position.price

        real_trade_size = trade_size
        if trade_size > 0:
            # 买现货的时候手续费从币扣除
            real_trade_size = trade_size - fee_symbol
        hold_size, hold_price, opened_size, closed_size = self.position.update(real_trade_size, trade_price)

        self.trade_count += 1

        self.fee_usdt += fee_usdt
        self.fee_bnb += fee_bnb
        self.fee_symbol += fee_symbol

        net_pnl = 0
        if trade_size > 0:
            pass

            # if self.asset == "BTC-USDT":
            #     print("Buy asset: %s, dt: %s, hold_size: %.8f, opened_size: %.8f, trade_size: %.8f, fee: %.8f" % (
            #     self.asset, dt, hold_size, opened_size, trade_size, fee))
        else:
            self.long_count += 1
            # 从金额扣除手续费(以后都不用bnb结算)
            net_pnl = (trade_price - old_price) * -closed_size - fee_usdt
            # if self.asset == "BTC-USDT":
            #     print("Sell asset: %s, dt: %s, hold_size: %.8f, closed_size: %.8f, trade_size: %.8f, fee: %.8f" %
            #           (self.asset, dt, hold_size, closed_size, trade_size, fee))
            self.close_pnl += net_pnl
            self.long_pnl = self.close_pnl

        return hold_size, hold_price, opened_size, closed_size, net_pnl

    def update_swap(self, dt, trade_size, trade_price, fee_usdt, fee_bnb, fee_symbol, lever):
        if self.asset == "USDT":
            return
        self.dt = dt
        self.lever = lever if lever else self.lever
        old_size, old_price = self.position.size, self.position.price
        hold_size, hold_price, opened_size, closed_size = self.position.update(trade_size, trade_price)

        self.fee_usdt += fee_usdt
        self.fee_bnb += fee_bnb

        _pnl = 0
        if closed_size < 0:
            self.trade_count += 1
            self.long_count += 1
            _pnl = (old_price - trade_price) * closed_size - fee_usdt
            self.long_pnl += _pnl
            self.win_count += 1 if _pnl > 0 else 0
        elif closed_size > 0:
            self.trade_count += 1
            self.short_count += 1
            _pnl = (old_price - trade_price) * closed_size - fee_usdt
            self.short_pnl += _pnl
            self.win_count += 1 if _pnl > 0 else 0
        else:
            pass
        self.close_pnl = self.long_pnl + self.short_pnl

        return hold_size, hold_price, opened_size, closed_size, _pnl

    def snapshot(self, date):
        dtstr = self.dt.strftime("%Y-%m-%d %H:%M:%S")
        return [
            date,
            self.asset,
            self.type,
            self.lever,
            dtstr,
            self.position.size,
            self.position.price if self.position.size != 0 else None,
            self.close_pnl,
            self.long_pnl,
            self.short_pnl,
            self.fee_usdt,
            self.fee_bnb,
            self.fee_symbol,
            self.trade_count,
            self.win_count,
            self.long_count,
            self.short_count
        ]


class Holdings:
    def __init__(self):
        self.holds = collections.defaultdict(HoldingItem)
        self.holds["USDT"] = HoldingItem("USDT", "SPOT")

    def update_swap(self, dt, asset, trade_size, trade_price, fee_usdt, fee_bnb, fee_symbol, lever):
        if asset == "USDT":
            return None
        if asset not in self.holds:
            self.holds[asset] = HoldingItem(asset, "SWAP")
        hold_size, hold_price, opened_size, closed_size, pnl = self.holds[asset].update_swap(dt, trade_size, trade_price,
                                                                                             fee_usdt, fee_bnb, fee_symbol, lever)
        # 从余额先把手续费给扣除
        self.update_usdt(dt, -fee_usdt)

        if pnl != 0:
            # 因为上面已经统一扣掉手续费, pnl把手续费又扣掉了
            self.update_usdt(dt, pnl + fee_usdt)

        return hold_size, hold_price, opened_size, closed_size, pnl

    def update_usdt(self, dt, trade_size):
        asset = "USDT"
        if asset not in self.holds:
            self.holds[asset] = HoldingItem(asset, "SPOT")
        return self.holds[asset].update_usdt(dt, trade_size)

    def update_spot(self, dt, asset, trade_size, trade_price, fee_usdt, fee_bnb, fee_symbol):
        if asset == "USDT":
            return None
        if asset not in self.holds:
            self.holds[asset] = HoldingItem(asset, "SPOT")
        hold_size, hold_price, opened_size, closed_size, pnl = self.holds[asset].update_spot(dt, trade_size, trade_price,
                                                                                        fee_usdt, fee_bnb, fee_symbol)

        if trade_size > 0:
            # 从现金扣掉
            value = trade_size * trade_price
            self.update_usdt(dt, -value)
        else:
            # 卖的时候扣掉手续费
            value = abs(trade_size) * trade_price - fee_usdt
            self.update_usdt(dt, value)

        return hold_size, hold_price, opened_size, closed_size, pnl

    def snapshot(self, date):
        result = []
        for k, v in self.holds.items():
            result.append(v.snapshot(date))
        return result


class DayStat:
    def __init__(self, accounts, timeframes, out, proxy):
        self.accounts = accounts
        self.timeframes = timeframes
        self.out = out
        self.proxy = proxy

    def stat(self):
        dates = pd.date_range(start=npv_start_date, end=datetime.datetime.today(), freq='1d')
        npv_df = pd.DataFrame(index=dates)

        holding = pd.DataFrame()
        transfer_list = []

        absent_list = set()

        trades_df_all = pd.DataFrame()
        for account in self.accounts:
            if account.endswith("future"):
                type = "SWAP"
            else:
                type = "SPOT"

            for his in params[account]["transfer_history"]:
                _dt = his[0][0:10]
                transfer_list.append([_dt, account, his[1]])
            analysis = TradeAnalysis(account, self.proxy)
            for tf in self.timeframes:
                df, absent_asset, trades_df = analysis.analysis(timeframe=tf, type=type)
                if absent_asset:
                    absent_list.update(absent_asset)

                if len(trades_df) > 0:
                    trades_df_all = trades_df_all.append(trades_df)

                df.loc[df[df["hold_size"].abs() < 0.001].index, "hold_size"] = 0
                df["value"] = df["hold_size"] * df["close"] * (df["type"] == "SPOT")

                df["paper_returns"] = (df["close"] - df["hold_price"]) * df["hold_size"]
                df['paper_returns'] = df['paper_returns'].fillna(value=0)
                df["value"] += ((df["type"] == "SWAP") * df['paper_returns'])
                df = df.round({"value": 4, "hold_size": 6, "hold_price": 10, "paper_returns": 4})
                df.to_csv(f"{self.out}/{account}-{tf}.csv", index=False)
                if len(df) > 0:
                    print(f"-----------[{account}]-[{tf}]-[{df.iloc[-1]['date']}]-------")
                if tf == "d":
                    tmp = df.groupby("date")[["value"]].agg(lambda x: np.nan if np.isnan(x).all() else x.sum())
                    tmp = tmp.rename(columns={"value": f"{account}"})
                    npv_df = npv_df.merge(tmp, left_index=True, right_index=True, how="left")

                    df["account"] = account
                    header = ["account", "date", "asset", "type", "lever", "hold_size", "hold_price", "trade_count", "close_pnl", "close", "value", "paper_returns"]
                    tmp1 = df[header]
                    # tmp1 = tmp1[tmp1["date"] >= tmp1["date"].unique()]  # 取最后两天
                    holding = holding.append(tmp1)

        # init_monet_fuze202102 = params["fuze202102"]["transfer_history"][0][1]

        for date1 in holding["date"].unique():
            # tmp1 = pd.DataFrame(columns=holding.columns, data=[["fuze202102",  date1, "USDT", "SPOT", 1,
                                                            # init_monet_fuze202102, 1, 0, 0, 1, init_monet_fuze202102, 0]])
            tmp1 = pd.DataFrame(columns=holding.columns)
            holding = holding.append(tmp1)

        # npv_df = npv_df.fillna(value=0)
        st_date = datetime.datetime.strptime(npv_start_date, "%Y-%m-%d") - datetime.timedelta(days=1)
        st_date = st_date.strftime("%Y-%m-%d")
        init_date = pd.date_range(st_date, st_date, freq='1d')

        if absent_list:
            print(f"Error: please update {','.join(absent_list)}")
            raise SyntaxError("数据需要更新")
        # 初始金额
        init_money = list(map(lambda x: params[x]["transfer_history"][0][1], self.accounts))

        init_df = pd.DataFrame(columns=self.accounts, index=init_date, data=[init_money])
        init_df = init_df.append(npv_df)
        # init_df["fuze202102"] = init_monet_fuze202102
        init_df = init_df.ffill()
        init_df["all"] = init_df.sum(axis=1)

        # 本金加仓历史
        transfer_df = pd.DataFrame(columns=["date", "account", "money"], data=transfer_list)
        transfer_df["date"] = pd.to_datetime(transfer_df["date"])
        transfer_df = transfer_df.set_index(["date", "account"])
        transfer_df = transfer_df.unstack()
        transfer_df.columns = list(map(lambda x: x[1] + "_init", transfer_df.columns))
        # for col in transfer_df.columns:
        #     transfer_df[col] = transfer_df[col].cumsum()
        # transfer_df = transfer_df.ffill()
        transfer_df["all_init"] = transfer_df.sum(axis=1)

        # 跟前面的顺序保持一致
        order_cols = list(map(lambda x: x + "_init", init_df.columns.tolist()))
        transfer_df = transfer_df[order_cols]

        init_df = init_df.merge(transfer_df, left_index=True, right_index=True, how="left")
        # init_df = init_df.ffill()
        init_df = init_df.fillna(value=0)
        # init_df = init_df.iloc[0:-1]
        init_df = init_df.round(4)
        return init_df, holding, trades_df_all


class TradeAnalysis:
    def __init__(self, name, proxy):
        home_dir = os.path.expanduser('~')
        account_path = os.path.join(home_dir, ".jupyter", "config.json")
        with open(account_path, 'r') as f:
            data = json.load(f)

        self.name = name
        api_key = data["account"][name]["apiKey"]
        secret = data["account"][name]["secret"]
        password = data["account"][name]["password"]
        self.params = params
        self.file_path = os.path.join(data["research"], "research")
        self.proxy = proxy
        config = {
            'apiKey': api_key,
            'secret': secret,
            "password": password,
            'enableRateLimit': True,  # required https://github.com/ccxt/ccxt/wiki/Manual#rate-limit
            'rateLimit': 500,
            'timeout': 20000,
            'options': {
                'defaultType': 'spot',
            },
            'nonce': lambda: str(int(time.time() * 1000))
        }

        if self.proxy:
            config["proxies"] = {
                'http': self.proxy,
                'https': self.proxy
            }

        self.exchange = ccxt.binance(config=config)

        cfg = json.load(open(os.path.join(os.path.expanduser('~'), ".jupyter", "config.json"), 'r'))
        ws_dir = cfg["ws"]
        self.data_dir = os.path.join(ws_dir, "data/binance/market")

    def fetch_spot_order_history(self, start_time):
        spot_trade_record_path = os.path.join(self.file_path, "现货历史成交记录.csv")
        _start_time = datetime.datetime.strptime(start_time, "%Y-%m-%d %H:%M:%S") - datetime.timedelta(hours=8)
        _start_time = _start_time.strftime("%Y-%m-%d %H:%M:%S")

        spot_df = pd.DataFrame()
        if os.path.exists(spot_trade_record_path):
            spot_df = pd.read_csv(spot_trade_record_path)
            _start_time = spot_df.iloc[-1]["date"]

        files = [e for e in sorted(os.listdir(self.file_path)) if e.startswith("导出历史成交记录-") and e.endswith(".xlsx")]
        if not files and len(spot_df) == 0:
            print("请先导出现货的最近一个月的历史成交记录")
            return []

        modified = False
        for file in files:
            _df = pd.read_excel(os.path.join(self.file_path, file))
            _df.columns = ["date", "symbol", "direction", "price", "volume", "amount", "fee", "fee_asset"]
            _df = _df.sort_values("date")
            _df = _df[_df["date"] > _start_time]
            if len(_df) != 0:
                spot_df = spot_df.append(_df)
                modified = True
        if modified:
            spot_df.to_csv(spot_trade_record_path, index=False)

        for file in files:
            os.remove(os.path.join(self.file_path, file))

        if len(spot_df) == 0:
            print("请先导出现货的最近一个月的历史成交记录")
            return []

        df = spot_df
        bnb_index = df["fee"][df["fee_asset"] == "BNB"].index
        df["fee_bnb"] = 0
        df["fee_bnb"].loc[bnb_index] = df["fee"][df["fee_asset"] == "BNB"]

        usdt_index = df["fee"][df["fee_asset"] == "USDT"].index
        df["fee_usdt"] = 0
        df["fee_usdt"].loc[usdt_index] = df["fee"][df["fee_asset"] == "USDT"]

        asset_index = df["fee"][(df["fee_asset"] != "USDT") & (df["fee_asset"] != "BNB")].index
        df["fee_symbol"] = 0
        df["fee_symbol"].loc[asset_index] = df["fee"][(df["fee_asset"] != "USDT") & (df["fee_asset"] != "BNB")]

        _sell_index = df["direction"][df["direction"] == "卖"].index
        df["volume"].loc[_sell_index] = df["volume"][_sell_index] * -1
        df["direction"].loc[_sell_index] = "sell"

        _buy_index = df["direction"][df["direction"] == "买"].index
        df["direction"].loc[_buy_index] = "buy"
        df["amount"] = df["volume"] * df["price"]

        del df["price"], df["fee"], df["fee_asset"]

        df = df.groupby(["date", "symbol", "direction"]).sum().reset_index()
        df["price"] = df["amount"] / df["volume"]
        df["profit"] = 0
        columns = ["date", "symbol", "direction", "price", "volume", "amount", "fee_usdt", "fee_bnb", "fee_symbol", "profit"]
        df = df[columns]
        return [e[1].to_dict() for e in df.iterrows()]

    def fetch_swap_order_history(self, start_time):
        swap_trade_record_path = os.path.join(self.file_path, "合约历史成交记录.csv")
        _start_time = datetime.datetime.strptime(start_time, "%Y-%m-%d %H:%M:%S") - datetime.timedelta(hours=8)
        _start_time = _start_time.strftime("%Y-%m-%d %H:%M:%S")

        swap_df = pd.DataFrame()
        if os.path.exists(swap_trade_record_path):
            swap_df = pd.read_csv(swap_trade_record_path)
            _start_time = swap_df.iloc[-1]["date"]

        swap_export_path = os.path.join(self.file_path, "导出历史成交记录.xlsx")

        modified = False
        if os.path.exists(swap_export_path):
            _df = pd.read_excel(os.path.join(self.file_path, "导出历史成交记录.xlsx"))
            _df.columns = ["date", "symbol", "direction", "price", "volume", "amount", "fee_usdt", "fee_asset", "profit",
                      "quote"]
            _df = _df.sort_values("date")
            _df = _df[_df["date"] > _start_time]
            if len(_df) != 0:
                swap_df = swap_df.append(_df)
                modified = True
        if modified:
            swap_df.to_csv(swap_trade_record_path, index=False)

        if os.path.exists(swap_export_path):
            os.remove(swap_export_path)

        if len(swap_df) == 0:
            print("请先导出合约的最近三个月的历史成交记录")
            return []

        df = swap_df
        df["fee_bnb"] = 0
        df["fee_symbol"] = 0
        df = df.sort_values("date")
        del df["fee_asset"], df["quote"]

        _sell_index = df["direction"][df["direction"] == "卖出"].index
        df["volume"].loc[_sell_index] = df["volume"][_sell_index] * -1
        df["direction"].loc[_sell_index] = "sell"

        _buy_index = df["direction"][df["direction"] == "买入"].index
        df["direction"].loc[_buy_index] = "buy"

        df["amount"] = df["volume"] * df["price"]

        del df["price"]

        df = df.groupby(["date", "symbol", "direction"]).sum().reset_index()
        df["price"] = df["amount"] / df["volume"]
        columns = ["date", "symbol", "direction", "price", "volume", "amount", "fee_usdt", "fee_bnb", "fee_symbol",
                   "profit"]
        df = df[columns]
        return [e[1].to_dict() for e in df.iterrows()]

    def fill_close(self, history):
        result = []
        absent_asset = []
        for data in history:
            asset = data[1]
            date = data[0]
            type = data[2]

            today1 = datetime.datetime.today() - datetime.timedelta(hours=8)
            if date.strftime("%Y-%m-%d") >= today1.strftime("%Y-%m-%d"):
                rs = self.fetch_close(dt_array=[(date, asset, None)])
                result.append(data + rs)
                continue

            if asset == "USDT":
                result.append(data + [1])
                continue
            # elif asset in ["OKB-USDT", "OKT-USDT"]:
            #     rs = self.fetch_close(dt_array=[(date, asset, None)])
            #     result.append(data + rs)
            #     continue
            asset_name = asset.replace("USDT", "_USDT")
            df = pd.read_csv(os.path.join(self.data_dir, "spot", "1d", f"{asset_name}.csv"))
            df["datetime"] = pd.to_datetime(df["datetime"])

            _date = date + datetime.timedelta(hours=8)
            df = df.set_index("datetime")
            if _date in df.index:
                result.append(data + [df.loc[_date]["close"]])
            else:
                result.append(data + [None])
                _name = asset.replace("USDT", "/USDT")
                if _name not in absent_asset:
                    absent_asset.append(_name)

        if absent_asset:
            print("pelase update %s" % ",".join(absent_asset))
        return result, absent_asset

    def analysis(self, timeframe="d", type="SPOT", start_time=None):
        start_time = start_time if start_time is not None else self.params[self.name]["start_time"]
        if type == "SPOT":
            result = self.fetch_spot_order_history(start_time)
        else:
            result = self.fetch_swap_order_history(start_time)
        history = []

        if "transfer_history" in self.params[self.name]:
            transfer_history = self.params[self.name]["transfer_history"]
        else:
            transfer_history = []

        last_his_dt = datetime.datetime.strptime("1900-01-01", "%Y-%m-%d")

        holds = Holdings()
        snapshot_dt, curr_dt = None, None

        close_trades_his = []

        for idx, item in enumerate(result):
            if float(item["volume"]) == 0:
                continue
            asset = item["symbol"]
            side = item["direction"]
            fee_usdt = float(item["fee_usdt"])
            fee_bnb = float(item["fee_bnb"])
            fee_symbol = float(item["fee_symbol"])
            if type not in ["SPOT", "SWAP"]:
                raise Exception(f"type [{type}] not supported.")
            trade_size = float(item["volume"])
            trade_price = float(item["price"])
            order_dt = datetime.datetime.strptime(item["date"], "%Y-%m-%d %H:%M:%S")
            snapshot_dt = current_dt(order_dt, timeframe)
            if not curr_dt:
                curr_dt = snapshot_dt

            for his in transfer_history:
                dt = datetime.datetime.strptime(his[0], "%Y-%m-%d %H:%M:%S")
                dt = dt - datetime.timedelta(hours=8)
                amount = his[1]
                if (last_his_dt < dt <= order_dt) or (idx == len(result) - 1 and dt > order_dt):
                    snapshot_dt = current_dt(dt, timeframe)
                    if curr_dt != snapshot_dt:
                        while curr_dt < snapshot_dt:
                            history += holds.snapshot(curr_dt)
                            curr_dt = next_dt(curr_dt, timeframe)

                    holds.update_usdt(dt, amount)
                    last_his_dt = dt

            if curr_dt != snapshot_dt:
                while curr_dt < snapshot_dt:
                    history += holds.snapshot(curr_dt)
                    curr_dt = next_dt(curr_dt, timeframe)

            if type == "SPOT":
                hold_size, hold_price, opened_size, closed_size, pnl = holds.update_spot(order_dt, asset, trade_size, trade_price, fee_usdt, fee_bnb, fee_symbol)
                if round(abs(closed_size), 4) > 0:
                    # 说明是平仓操作
                    close_trades_his.append(
                        [order_dt, asset, "SPOT", abs(closed_size), trade_price, round(abs(hold_size), 4), round(hold_price, 4), pnl, fee_usdt])
            elif type == "SWAP":
                hold_size, hold_price, opened_size, closed_size, pnl = holds.update_swap(order_dt, asset, trade_size, trade_price, fee_usdt, fee_bnb, fee_symbol, 5)
                if round(abs(closed_size), 4) > 0:
                    # 说明是平仓操作
                    close_trades_his.append(
                        [order_dt, asset, "SWAP", closed_size, trade_price, round(abs(hold_size), 4), round(hold_price, 4), pnl, fee_usdt])

            last_his_dt = order_dt
        # 最后再做一次快照
        if curr_dt:
            curr_dt = snapshot_dt
            history += holds.snapshot(curr_dt)

            # 好长时间没调仓, 把已经产生的持仓补上
            latest_snapshot_dt = current_dt(datetime.datetime.today(), timeframe)
            while curr_dt < latest_snapshot_dt:
                curr_dt = next_dt(curr_dt, timeframe)
                history += holds.snapshot(curr_dt)

        header = [
            "date", "asset", "type", "lever", "order_dt", "hold_size", "hold_price", "close_pnl", "long_pnl",
            "short_pnl", "fee_usdt", "fee_bnb", "fee_symbol", "trade_count", "win_count", "long_count", "short_count", "close"
        ]
        # print("fetch history")
        history, absent_asset = self.fill_close(history)
        # print("fetch close")
        df = pd.DataFrame(columns=header, data=history)
        df = df.round({"hold_size": 6, "hold_price": 10, "close_pnl": 4, "long_pnl": 4, "short_pnl": 4,
                       "fee_usdt": 4, "fee_bnb": 4, "fee_symbol": 4, "trade_amount": 4})

        header1 = ["date", "asset", "type", "closed_size", "trade_price", "hold_size", "hold_Price", "pnl", "fee_usdt"]
        trade_df = pd.DataFrame(columns=header1, data=close_trades_his)
        trade_df = trade_df.round({"hold_size": 6, "closed_size": 6, "trade_price": 10, "hold_price": 10, "pnl": 4, "fee_usdt": 4})
        return df, absent_asset, trade_df

    def fetch_close(self, timeframe="1d", dt_array=None):
        result = []
        for dt, symbol, _ in dt_array:
            if symbol == "USDT":
                result.append(1)
            elif (dt, symbol) in CLOSE_CACHE:
                result.append(CLOSE_CACHE[(dt, symbol)])
            else:
                _symbol = symbol.replace("USDT", "/USDT")
                data = self.exchange.fetch_ohlcv(symbol=_symbol, timeframe=timeframe, limit=1)
                result.append(data[0][4])
                print(f"fetch close dt: {dt}, symbol: {symbol}, close: {data[0][4]}")
                CLOSE_CACHE[(dt, symbol)] = data[0][4]
        return result

@cli.command()
# @click.option('-d', '--data-bundle-path', default=os.path.expanduser('~/.rqalpha'), type=click.Path(file_okay=False))
@click.option("--account", default="binance-main,binance-main-future")
@click.option('--timeframe', default="d")
@click.option('--proxy', type=click.STRING, default=None)
@click.option('--out', default="/Users/wudi/Workspace/jupyter-analysis/research")
def analysis(account, timeframe, out, proxy):
    if proxy is not None and proxy == "http":
        proxy = "127.0.0.1:41091"

    accounts = account.split(",")
    timeframes = timeframe.split(",")
    daystat = DayStat(accounts, timeframes, out, proxy)
    init_df, holding, trades_df = daystat.stat()
    # 存在合并index有相同的
    holding = holding.reset_index()

    # 为了兼容之前的表格
    init_df = init_df.iloc[1:]
    init_df.to_csv(f"{out}/npv.csv", header=True)

    trades_df.to_csv(f"{out}/trades.csv")

    swap_holding = holding[holding["type"] == "SWAP"]
    swap_margin = swap_holding["hold_size"] * swap_holding["hold_price"] / swap_holding["lever"]
    holding.loc[swap_holding.index, "lever"] = swap_margin

    holding.loc[holding[holding["type"] == "SPOT"].index, "lever"] = 0

    holding.rename(columns={"lever": "margin"}, inplace=True)
    holding = holding.round(({"margin": 4, "paper_returns": 4, "hold_price": 10}))

    trade_change = pd.DataFrame()
    for idx in range(3):
        # 获取对比的日期, 与昨天比, 与上周比, 与上月比
        today = datetime.datetime.today() - datetime.timedelta(days=idx)
        # dates = [current_dt(today), previous_dt(today), previous_dt(today, "w"), previous_dt(today, "m")]
        dates = [current_dt(today), previous_dt(today)]
        # dates_str = ["今日", "昨日", "上周", "上月"]
        dates_str = ["今日", "昨日"]
        tmp = holding[holding["date"].isin(dates)]
        tmp = tmp.set_index(["date", "asset", "account"])
        _hold_size = tmp.unstack().unstack().T.loc["hold_size"]
        _hold_price = tmp.unstack().unstack().T.loc["hold_price"]
        _trade_count = tmp.unstack().unstack().T.loc["trade_count"]
        _close = tmp.unstack().unstack().T.loc["close"]
        _close_pnl = tmp.unstack().unstack().T.loc["close_pnl"]
        result = pd.DataFrame(index=_hold_size.index)
        result["date"] = today.strftime("%Y%m%d")

        today_date = dates[0]
        for index, date in enumerate(dates[1:]):
            # _date_str = date.strftime("%Y%m%d")[-4:]
            _date_str = dates_str[1:][index]
            result[_date_str + "持仓变化"] = _hold_size[today_date] - _hold_size[date]
            # result[_date_str + "_hold_size"] = _hold_size[date]
            result[_date_str + "交易变化"] = _trade_count[today_date] - _trade_count[date]
            result[_date_str + "收益率"] = _close[today_date] / _close[date] - 1
            no_change_ret1 = _hold_size[date] * (_close[today_date] - _hold_price[date]) + _close_pnl[date]    # 之前持仓收益
            no_change_ret2 = _hold_size[today_date] * (_close[today_date] - _hold_price[today_date]) + _close_pnl[today_date]
            result[_date_str + "盈亏"] = no_change_ret2 - no_change_ret1

        result.fillna(value=0, inplace=True)
        result = result.round(4)

        cols = list(filter(lambda x: x.endswith("盈亏"), result.columns))
        conditions = None
        for col in cols:
            if conditions is None:
                conditions = result[col] != 0
            else:
                conditions = conditions & (result[col] != 0)

        result = result[conditions]
        result = result.reset_index()
        result = result[result["asset"] != "USDT"]

        result = result.sort_values(["account", "asset"])
        trade_change = trade_change.append(result)

    trade_change.to_csv(f"{out}/holding-diff.csv", index=False)

    # 过滤掉目前持仓是0的资产
    holding = holding[holding["value"] != 0]

    for date in pd.to_datetime(holding["date"].unique()[-7:]).strftime("%Y%m%d"):
        tmp = holding[holding["date"] == date]
        del tmp["index"]
        del tmp["trade_count"]
        tmp.to_csv(f"{out}/holding-{date}.csv", index=False)

@click.group()
def trade_binance():
    pass


trade_binance.add_command(analysis)

if __name__ == "__main__":
    trade_binance()